﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Greve
{
	public class NetworkClient
	{
        public delegate void TickHandler();

        public event TickHandler onUpdate;
		~NetworkClient()
		{
			shutdown();
		}

		private TcpClient clientClient;
		private NetworkStream clientStream;
		private ASCIIEncoding encoder = new ASCIIEncoding();
		private TcpListener tcpListener;
		private Thread listenThread;

		public bool on = false;
        public String lastSentMessage;
		public void start(string ip, int portNr)
		{
			byte[] message = new byte[4096];
			int bytesRead;

			clientClient = new TcpClient();

			//Work as simple ip and portnr
			IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ip), portNr);

			tcpListener = new TcpListener(IPAddress.Any, 3000);

			//Try to connect to server
			try
			{
				clientClient.Connect(serverEndPoint);
				clientStream = clientClient.GetStream();
				//Start new thread to listen from server
				listenThread = new Thread(new ThreadStart(signalFromServer));
				listenThread.IsBackground = true;
				listenThread.Start();
				on = true;
				//Program.forminstance.updateChatbox("Connected to server");
			}
			catch
			{
				//Program.forminstance.updateChatbox("Failed to connect to server");
				//Program.forminstance.button2.Enabled = true;
				MessageBox.Show("No Server: Try again later");
			}
		}
		public void send(string t)
		{
			byte[] buffer = encoder.GetBytes(t);

			clientStream.Write(buffer, 0, buffer.Length);
			clientStream.Flush();
		}
		public void shutdown()
		{
			//the client has disconnected from the server
			if (clientClient != null)
				clientClient.Close();
			if (clientStream != null)
				clientStream.Close();
			if (listenThread != null)
				listenThread.Abort();
			if (tcpListener != null)
				tcpListener.Stop();
			on = false;
		}
		public void signalFromServer()
		{
			byte[] message = new byte[4096];
			int bytesRead;

			while (on)
			{
				bytesRead = 0;

				try
				{
					//blocks until a client sends a message
					bytesRead = clientStream.Read(message, 0, 4096);
				}
				catch
				{
					//a socket error has occured
					on = false;
					shutdown();
					break;
				}

				if (bytesRead == 0)
				{
					on = false;
					shutdown();
					break;
				}
                
				lastSentMessage = encoder.GetString(message, 0, bytesRead);
                if (onUpdate != null)
                    onUpdate();
				System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
			}
		}

		public void send(Person person)
		{
			send("PersonID" + person.ID);
		}
	}

	public class NetworkServer
	{
		public NetworkServer()
		{
		}

		public NetworkServer(int _port)
		{
			port = _port;
		}

		~NetworkServer()
		{
			foreach (KeyValuePair<TcpClient, string> entry in clientsOP)
			{
				entry.Key.Close();
				clientsThread[entry.Key].Abort();
			}
			clientsOP.Clear();
			clientsThread.Clear();
            if (result != null)
            {
                result.Close();
                resultTread.Abort();
            }
            if (listenThread != null)
				listenThread.Abort();
			if (tcpListener != null)
				tcpListener.Stop();
			on = false;
		}

		public bool on = false;
		private int port = 3000;
		public static string registerID = "RegisterName: ";
		public static string penaltyID = "Penalty: ";
		static string resultUpdateID = "resultUpdate: ";
		public static string resultUpdatePointsID = resultUpdateID + "PointsID: ";

		public string latestMSG = "";
		public List<string> chatHistory;

		public Dictionary<string, string> updateInfo = new System.Collections.Generic.Dictionary<string, string>();

		public int maxConnection = 7;

		private TcpListener tcpListener;
		private Thread listenThread;
		public Dictionary<TcpClient, string> clientsOP = new Dictionary<TcpClient, string>();
        public TcpClient result;
        private Thread resultTread;
		public CupRunning runningCup;
		private Dictionary<TcpClient, Thread> clientsThread = new Dictionary<TcpClient, Thread>();

		//currently does nothing
		public void update()
		{
			foreach (KeyValuePair<TcpClient, string> entry in clientsOP)
			{
				HandleClientComm(entry.Key);
			}
		}

		public void start()
		{
			this.tcpListener = new TcpListener(IPAddress.Any, port);
			this.listenThread = new Thread(new ThreadStart(ListenForClients));
			this.listenThread.Start();
			listenThread.IsBackground = true;
			on = true;
		}

		private void ListenForClients()
		{
			this.tcpListener.Start();

			while (on)
			{
				//blocks until a client has connected to the server
				TcpClient client;
				{
					client = this.tcpListener.AcceptTcpClient();
					if (client != null)
					{
						clientsOP.Add(client, clientsOP.Count.ToString());
						//create a thread to handle communication
						//with connected client
						clientsThread.Add(client, new Thread(new ParameterizedThreadStart(HandleClientComm)));
						clientsThread[client].IsBackground = true;
						clientsThread[client].Start(client);
					}
				}
			}
		}

		private void HandleClientComm(object client)
		{
			TcpClient ttcpClient = (TcpClient)client;
			NetworkStream clientStream = ttcpClient.GetStream();

			byte[] message = new byte[4096];
			int bytesRead;

			while (on)
			{
				bytesRead = 0;

				try
				{
					//blocks until a client sends a message
					bytesRead = clientStream.Read(message, 0, 4096);
				}
				catch
				{
					//a socket error has occured
					//on = false;
                    if (!client.Equals(result))
                    {
                        clientsOP.Remove(ttcpClient);
                        clientsThread[ttcpClient].Abort();
                        clientsThread.Remove(ttcpClient);
                    }
                    else
                    {
                        result = null;
                        resultTread.Abort();
                        resultTread = null;
                    }

					break;
				}

				if (bytesRead == 0)
				{
					//the client has disconnected from the server
                    if (!client.Equals(result))
                    {
                        clientsOP.Remove(ttcpClient);
                        clientsThread[ttcpClient].Abort();
                        clientsThread.Remove(ttcpClient);
                    }
                    else
                    {
                        result = null;
                        resultTread.Abort();
                        resultTread = null;
                    }
					break;
				}

				//message has successfully been received
				ASCIIEncoding encoder = new ASCIIEncoding();
				string a = encoder.GetString(message, 0, bytesRead);
				handleString(a,ttcpClient);
				chatHistory.Add(a);
				latestMSG = a;
                if(clientsOP.ContainsKey(ttcpClient))
				    runningCup.updateChatbox(clientsOP[ttcpClient] + ": " + a);
				System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
			}
			ttcpClient.Close();
			clientStream.Close();
		}
		void handleString(string a,	TcpClient ttcpClient)
		{
			if (a.Contains(registerID))
			{
				string name = a.Remove(0, registerID.Length);
				clientsOP[ttcpClient] = name;
			}
            if(a.Contains("[Result]"))
            {
                result = ttcpClient;
                resultTread = clientsThread[ttcpClient];
                clientsThread.Remove(ttcpClient);
                clientsOP.Remove(ttcpClient);
            }
			if (a.Contains(resultUpdatePointsID))
			{

			}
				
		}




        public void sendResult(string t)
        {
            send(t, result);
        }

		public void send(string t)
		{
			foreach (KeyValuePair<TcpClient, string> entry in clientsOP)
			{
				send(t, entry.Key);
			}
		}
		private void send(string t, TcpClient client)
		{
			if (on)
			{
				NetworkStream clientStream = client.GetStream();
				ASCIIEncoding encoder = new ASCIIEncoding();
				byte[] buffer = encoder.GetBytes(t);

				clientStream.Write(buffer, 0, buffer.Length);
				clientStream.Flush();
			}
		}
	}
}